function cspat_renderer() {
	
	this.data_array = [];
	
	this.add_json_data = function(json) {
		if (!this.data_array) {
			this.data_array = [];
		}
		this.data_array.push(json);
	};
	
	this.remove_all_json_data = function() {
		this.data_array = [];
	};
	
	this.remove_json_data = function(i) {
		if (!this.data_array) {
			return;
		}
		if (i < this.data_array.length) {
			this.data_array.splice(i, 1);
		}
	};
	
	this.change_current_status = function(value) {
		this.change_value("cspat_status", value);
		if (value == "Done") {
			this.change_css("cspat_status", "highlight", false);
		} else {
			this.change_css("cspat_status", "highlight", true);
		}
	};

	this.change_css = function(id, value, add) {
		var selector = id;
		if (id.charAt(0) != '#' && id.charAt(0) != '.') {
			selector = "#" + selector;
		}
		if (add) {
			$(selector).addClass(value);
		} else {
			$(selector).removeClass(value);
		}
	};

	this.change_value = function(id, value) {
		var selector = id;
		if (id.charAt(0) != '#' && id.charAt(0) != '.') {
			selector = "#" + selector;
		}
		$(selector).html(value);
	};
	
	this.generate_time_graph = function(data) {
		$(item_graph_selector).html(time_graph.render(data));
	};
	
	// use json to render new manipulation
	this.render_manipulation = function(json) {
		this.add_json_data(json);
		create_manipulation(json);
		toggle_exports(true);
	};
	
	// use json array to render new manipulations
	this.render_manipulations = function(json_array) {
		json_array.forEach(function(json) {
			this.render_manipulation(json);
		}, this);
	};

	// for control
	var port = new cspat_port(this);
	
	// for table data rendering
	var cspat_web_data = new web_data();
	var cspat_isrvr_data = new isrvr_data();
	var cspat_rsrc_data = new rsrc_data();
	var cspat_js_data = new js_data();
	
	// for time elapsed bar renderings
	var time_graph = new time_graph_renderer();

	// css selectors
	var rename_dialog_selector = "#rename";
	var rename_value_selector = "#name";
	var accordion_selector = "#accordion";
	var info_tabs_selector = ".info_tabs";
	var manip_name_selector = "#accordion > h3 > span.manip-name"; //".manip-name";
	var item_graph_selector = "#time_graph";
	var cspat_status_selector = "#cspat_status";
	var delete_selector = ".ui-icon-minus";
	var export_all_selector = "#export_all";
	var export_basic_info_selector = "#export_basic_info";
	//var export_current_selector = "#export_current";
	var button_bar_selector = ".button-bar";
	var button_start_selector = "#start";
	var button_stop_selector = "#stop";
	var button_reset_selector = "#reset";
	
	// hold for the maximun manipulation id
	var max_id = 0;
	
	// toggle on/off export buttons
	var export_on = true;
	
	var that = this;
	
	var rename_tooltip_options = {
			content: "Click to rename",
			show: { effect: 'slideDown' },
			open: function (event, ui) {
           		setTimeout(function () {
               		$(ui.tooltip).hide('fast');
           		}, 1000);}
		};
	
	var accordion_icons = {
			header: "ui-icon-triangle-1-e",
			activeHeader: "ui-icon-triangle-1-s"
		};
	
	var rename_open_dialog = function(e) {
		e.preventDefault();
		e.stopPropagation();
		
		$(rename_dialog_selector).dialog( "open" );
		$(rename_dialog_selector).data('target', e.target);
		$(rename_dialog_selector).dialog("option", "position", {
	   		my: "left top",
	   		at: "right bottom",
	   		of: event,
	   		offset: "5 5"
	  	});
	};
	
	var generate_accordion = function() {
		$(accordion_selector).accordion({
			icons: accordion_icons,
			collapsible: true,
			active: 'none',
			heightStyle: "content"
		});
	};
	
	var refresh_accordion = function() {
		$(accordion_selector).accordion( "refresh" );
	};
	
	var generate_tabs = function() {
		$(info_tabs_selector).each(function() {
			$(this).tabs();
		});
	};
	
	var generate_tab_last = function() {
		$(info_tabs_selector).last().tabs();
	};
	
	var generate_tooltips = function() {
		$(manip_name_selector).each(function() {
			$(this).attr("title", "").tooltip(rename_tooltip_options);
		});
	};
	
	var generate_tooltips_last = function() {
		$(manip_name_selector).last().attr("title", "").tooltip(rename_tooltip_options);
	};
	
	var remove_manipulation = function(e) {
		var ptn = /^#(\d+) (.*)$/;
		
		var delete_span = $(e.target);
		
		var index = $(delete_selector).index(delete_span);
		that.remove_json_data(index);
		if (that.data_array && that.data_array.length == 0) {
			toggle_exports(false);
		}
		
		var h3 = delete_span.parent();
		var tabs = h3.next();
		tabs.remove();
		h3.remove();
		
		// change manipulation number
		$(manip_name_selector).each(function(index) {
			match = $(this).text().match(ptn);
			if (match) {
				$(this).text("#" + (index + 1) + " " + match[2]);
			}
		});
	};
	
	var remove_all_manipulations = function() {
		toggle_exports(false);
		that.change_current_status("Done");
		that.remove_all_json_data();
		$(accordion_selector).html("");
		refresh_accordion();
	};
	
	var export_json_manip_header = function(json) {
		var col_delim = ',';
		var row_delim = '\r\n';
		var csv = '';
		csv += "Manipulation: " + col_delim + json.name + row_delim;
		csv += "Total: " + col_delim + json.statistics.total + row_delim;
		csv += "ISrvr: " + col_delim + json.statistics.isrvr + row_delim;
		csv += "Web: " + col_delim + json.statistics.web + row_delim;
		csv += "Rsrc: " + col_delim + json.statistics.rsrc + row_delim;
		csv += "JS: " + col_delim + json.statistics.js + row_delim;
		csv += row_delim;
		return csv;
	};
	
	var export_json = function(json) {
		var csv = export_json_manip_header(json);
		
		cspat_web_data.remove_all_rows();
		cspat_web_data.rows = json.web || [];
		csv += cspat_web_data.export_csv();
		
		cspat_isrvr_data.remove_all_rows();
		cspat_isrvr_data.rows = json.iserver || [];
		csv += cspat_isrvr_data.export_csv();
		
		cspat_rsrc_data.remove_all_rows();
		cspat_rsrc_data.rows = json.resources || [];
		csv += cspat_rsrc_data.export_csv();
		
		cspat_js_data.remove_all_rows();
		cspat_js_data.rows = json.js || [];
		csv += cspat_js_data.export_csv();
		return csv;
	};

	var export_json_basic_info = function(json) {
		var csv = export_json_manip_header(json);
		return csv;
	};
	
	var export_current_manipulation = function(filename) {
		if (!that.data_array || that.data_array.length == 0) {
			return;
		}
		var json = that.data_array[that.data_array.length - 1];
		var csv = export_json(json);
		var csv_data = 'data:application/csv;charset=utf-8,' + encodeURIComponent(csv);
			
		$(this)
            .attr({
            'download': filename,
                'href': csv_data,
              'target': '_blank'
        });
	};

	var export_basic_info = function(filename) {
		if (!that.data_array) {
			return;
		}
		var row_delim = '\r\n',
			csv = that.data_array.map(function(json) {
				return export_json_basic_info(json);
			}).join(row_delim),
			csv_data = 'data:application/csv;charset=utf-8,' + encodeURIComponent(csv);

		$(this)
            .attr({
            'download': filename,
                'href': csv_data,
              'target': '_blank'
        });
	};
	
	var export_all_manipulation = function(filename) {
		if (!that.data_array) {
			return;
		}
		
		var row_delim = '\r\n',
		
			csv = that.data_array.map(function(json) {
				return export_json(json);
			}).join(row_delim),
			
			csv_data = 'data:application/csv;charset=utf-8,' + encodeURIComponent(csv);
			
		$(this)
            .attr({
            'download': filename,
                'href': csv_data,
              'target': '_blank'
        });
	};
	
	var toggle_exports = function(on) {
		if (on == export_on) {
			return;
		}
		export_on = on;
		if (on) {
			//$(export_current_selector).show();
			$(export_basic_info_selector).show();
			$(export_all_selector).show();
		} else {
			//$(export_current_selector).hide();
			$(export_basic_info_selector).hide();
			$(export_all_selector).hide();
		}
	};
	
	var bind_rename_dialog = function() {
		$(manip_name_selector).bind("click", rename_open_dialog);
	};
	
	var bind_rename_dialog_last = function() {
		$(manip_name_selector).last().bind("click", rename_open_dialog);
	};
	
	var bind_delete = function() {
		$(delete_selector).each(function() {
			$(this).bind("click", remove_manipulation);
		});
	};
	
	var bind_delete_last = function() {
		$(delete_selector).last().bind("click", remove_manipulation);
	};
	
	var bind_export = function() {
//		$(export_current_selector).button().on("click", function(e) {
//			export_current_manipulation.apply(this, ["current_manipulation.csv"]);
//		});
		$(export_basic_info_selector).button().on("click", function(e) {
			export_basic_info.apply(this, ["basic_info.csv"]);
		});
		$(export_all_selector).button().on("click", function(e) {
			export_all_manipulation.apply(this, ["all_manipulations.csv"]);
		});
	};
	
	var bind_start = function() {
		$(button_start_selector).click(function() {
			$(button_start_selector).attr("disabled", true).addClass("ui-state-disabled");
			$(button_stop_selector).attr("disabled", false).removeClass("ui-state-disabled")
				.removeClass("ui-state-hover").removeClass("ui-state-focus");
			port.post_msg(MSG_TYPE_START_CSPAT);
		});
	};
	
	var bind_stop = function() {
		$(button_stop_selector).click(function() {
			$(button_start_selector).attr("disabled", false).removeClass("ui-state-disabled")
				.removeClass("ui-state-hover").removeClass("ui-state-focus");
			$(button_stop_selector).attr("disabled", true).addClass("ui-state-disabled");
			port.post_msg(MSG_TYPE_STOP_CSPAT);
		});
	};
	
	var bind_reset = function() {
		$(button_reset_selector).click(remove_all_manipulations);
	};
	
	var get_max_tab_id = function () {
		var last = $(info_tabs_selector).last();
		if (last == null || last == undefined) {
			return 0;
		}
		var last_id = last.attr( "id" );
		var ptn = /^tabs(\d+)/;
		match = ptn.exec(last_id);
		if (match == null) {
			return 0;	
		}
		return parseInt(match[1]);
	};
	
	var get_accordion_tab_num = function() {
		return $(info_tabs_selector).length;
	};
	
	//var manip_header_template = "<h3><span class='manip-name'>##{id} #{name}</span> | <span>Total: #{total}ms</span> | <span>Isrvr: #{isrvr}ms</span> | <span>Web: #{web}ms</span> | <span>Rsrc: #{rsrc}ms</span> | <span>JS: #{js}ms</span> | <span>Wait: #{wait}ms</span><span class='ui-icon ui-icon-minus'></span></h3>";
	var manip_header_template = "<h3><span class='manip-name'>##{id} #{name}</span> | <span>Total: #{total}ms</span> | <span>Isrvr: #{isrvr}ms</span> | <span>Web: #{web}ms</span> | <span>Rsrc: #{rsrc}ms</span> | <span>JS: #{js}ms</span><span class='ui-icon ui-icon-minus'></span></h3>";

	var create_header = function (name, statistics, id) {
		var default_time = 0;
		var total = statistics.total || default_time;
		var isrvr = statistics.isrvr || default_time;
		var web = statistics.web || default_time;
		var rsrc = statistics.rsrc || default_time;
		var js = statistics.js || default_time;
		//var wait = statistics.wait || default_time;
		var name_value;
		var cur_id = id || (get_accordion_tab_num() + 1);
		if (!name || name == "") {
			name_value = "Unnamed";
		} else {
			name_value = name;
		}
		var html = manip_header_template
					.replace("#{id}", cur_id.toString())
					.replace("#{name}", name_value)
					.replace("#{total}", total.toString())
					.replace("#{isrvr}", isrvr.toString())
					.replace("#{web}", web.toString())
					.replace("#{rsrc}", rsrc.toString())
					.replace("#{js}", js.toString());
		//			.replace("#{wait}", wait.toString());
		$(accordion_selector).append(html);
	};
	
	var manip_div_template = "<div id='tabs#{id}' class='info_tabs'>#{tab_list}</div>";
	var manip_div_tab_header_list = "<ul>" + 
		"<li><a href='#tabs#{id}-1'>Web</a></li>" + 
		"<li><a href='#tabs#{id}-2'>ISrvr</a></li>" + 
		"<li><a href='#tabs#{id}-3'>Rsrc</a></li>" + 
		"<li><a href='#tabs#{id}-4'>JS</a></li>" +
		"</ul>";
	
	function create_inner_tabs(id, json) {
		var html = manip_div_template.replace("#{id}", id.toString());
		var tab_header_list = manip_div_tab_header_list.replace(/#{id}/g, id);
		
		var tab_divs = "";
		// web
		tab_divs += "<div id='tabs" + id.toString() + "-1'>";
		cspat_web_data.remove_all_rows();
		cspat_web_data.rows = json.web || [];
		tab_divs += cspat_web_data.get_table_html();
		tab_divs += "</div>";
		// isrvr
		tab_divs += "<div id='tabs" + id.toString() + "-2'>";
		cspat_isrvr_data.remove_all_rows();
		cspat_isrvr_data.rows = json.iserver || [];
		tab_divs += cspat_isrvr_data.get_table_html();
		tab_divs += "</div>";
		// rsrc
		tab_divs += "<div id='tabs" + id.toString() + "-3'>";
		cspat_rsrc_data.remove_all_rows();
		cspat_rsrc_data.rows = json.resources || [];
		tab_divs += cspat_rsrc_data.get_table_html();
		tab_divs += "</div>";
		// js
		tab_divs += "<div id='tabs" + id.toString() + "-4'>";
		cspat_js_data.remove_all_rows();
		cspat_js_data.rows = json.js || [];
		tab_divs += cspat_js_data.get_table_html();
		tab_divs += "</div>";
		
		var inner_html = tab_header_list + tab_divs;
		html = html.replace("#{tab_list}", inner_html);
		
		$(accordion_selector).append(html);
	}
	
	var create_manipulation = function(json) {
		max_id++;
		create_header(json.name, json.statistics);
		create_inner_tabs(max_id, json);
		refresh_accordion();
		generate_tab_last();
		generate_tooltips_last();
		bind_rename_dialog_last();
		bind_delete_last();
	};
	
	var style_buttons = function() {
		$(button_bar_selector).children().each(function(i) {
			$(this).button();
		});
	};
	
	var init = function() {
		$( function() {
			$(rename_dialog_selector).dialog({
	      		autoOpen: false,
	      		height: 100,
	      		width: 160,
	      		modal: true,
	      		resizable: false,
	      		buttons: {
	        		"Ok": function() {
						name = $(rename_value_selector).val();
						if (name == undefined || name == "") {
							// do nothing
						} else {
							// var $led = $(rename_dialog_selector);
	        				// var target = $led.data( "target" );
	        				var target = $(this).data( "target" );
							var old_name = target.innerHTML;
							var ptn = /^(#\d+) /;
							var match = ptn.exec(old_name);
							if (match == null) { // this should not happen
								target.innerHTML = name;
							} else if (ptn.exec(name) == null) { // is this check necessary?
								target.innerHTML = match[1] + " " + name; // actually we only hope this happen
								// get index
								var index = $(manip_name_selector).index($(target));
								// change manipulation name
								that.data_array[index].name = name;
							} else {
								target.innerHTML = name;
							}
						}
	            		$(this).dialog( "close" );
	        		},
	        		Cancel: function() {
	          			$(this).dialog( "close" );
	        		}
	      		},
	      		close: function() {
					$(this).dialog( "close" );
	      		}
	    	});
	    	
	    	style_buttons();
	    	bind_start();
	    	bind_stop();
	    	bind_reset();
	    	
	    	generate_accordion();
	    	generate_tabs();
	    	generate_tooltips();
	    	bind_rename_dialog();
	    	bind_delete();
	    	bind_export();
	    	
	    	toggle_exports(false);
	    	
	    	max_id = get_max_tab_id();
		});
	};
	
	init();

}

var cspat = new cspat_renderer();

function time_graph_renderer() {
	this.render = function(data) {
		create_time_bar(data);
	};
	
	// TODO:
	var create_time_bar = function(data) {
		html = "<svg class='chart' width='420' height='19'>" + 
			  	"<g transform='translate(0,0)'>" +
			    	"<rect width='40' height='15'></rect>" + 
			//"    <text x='37' y='9.5' dy='.35em'>2</text>" + 
				"</g>" + 
				"<g transform='translate(45,0)'>" +
					"<rect width='15' height='15'></rect>" +
			//"    <text x='52' y='9.5' dy='.35em'>4</text>" +
				"</g>" +
				"<g transform='translate(65,0)'>" +
					"<rect width='60' height='15'></rect>" +
			//"    <text x='112' y='9.5' dy='.35em'>2</text>" +
				"</g>" +
				"</svg>";
		return html;
	};
}
